/*
 *
 * CSymbolTable
 *		Symbol table is realized by the Hash table;
 *		the same name item (different level) is
 *		organized with a link stack. The top of
 *		the stack is the highest level item.
 *
 */
package compiler;
import java.util.Hashtable;
import java.util.Stack;

import compiler.error.CRedefineError;
import compiler.error.CUndefineError;


class CSymbolTable
{
	private Hashtable table;
		//Symbol table is create as a Hash table
	private Stack stack;
		//the symbol level infomation is saved in stack

	//SymbolTable constructor
	//	register "true", "false", "integer", "boolean"
	CSymbolTable() throws CRedefineError
	{
		table = new Hashtable(5000);
		stack = new Stack();
		Register("true", new CBoolConst(0, true));
		Register("false", new CBoolConst(0, false));
		Register("integer", new CIntType());
		Register("boolean", new CBooleanType());
		Register("double", new CDoubleType());
		Register("read", new CReadProc());
		Register("write", new CWriteProc(false));
		Register("writeln", new CWriteProc(true));
	}

	//Star with a new level
	void NewLevel() { stack.push(null); }

	//Register the Symbol named with <NAME>

	void Register(String name, CSymbol s) throws CRedefineError
	{
		if (table.containsKey(name))
		{
			CSymbolItem item = (CSymbolItem) table.get(name);
			if (item.info.level == s.level)
				throw new CRedefineError(name);
			item.next = new CSymbolItem(item.info, item.next);
			item.info = s;
		}
		else
		{
			table.put(name, new CSymbolItem(s));
		}
		stack.push(name);
		//System.out.println("Register " + name + " as " + s);
	}

	//Test if the named symbol is in the symbol table
	boolean Has(String name)
	{
		return table.containsKey(name);
	}

	//Get the infomation of the symbol with the name
	CSymbol GetInfo(String name) throws CUndefineError
	{
		CSymbolItem item = (CSymbolItem) table.get(name);
		if (item == null) throw new CUndefineError(name);
		return item.info;
	}

	//Removed the symbols of current level
	void RemoveCurrentLevel()
	{
		String key;
		CSymbolItem item = null;
		while (true)
		{
			key = (String) stack.pop();
			if (key == null) return;
			item = (CSymbolItem) table.get(key);
			if (item.next == null)
				table.remove(key);
			else
			{
				item.info = item.next.info;
				item.next = item.next.next;
			}
		}
	}
}

